/*
 * Copyright (c) 2018 Actions Semiconductor, Inc
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include "errno.h"
#include <misc/byteorder.h>
#include <misc/printk.h>
#include <gpio.h>
#include <board.h>
/* #include <display/panel_ssd1306_128x64.h> */

#define SYS_LOG_DOMAIN "SSD1306"
#define SYS_LOG_LEVEL 4
#include <logging/sys_log.h>

#ifdef CONFIG_SSD1306_DEV_TYPE_SPI
#include <spi.h>
#endif

/************************************************************************/
const unsigned char  F6x8[100][6] = {

{0x00, 0x00, 0x00, 0x00, 0x00, 0x00},/* sp */
{0x00, 0x00, 0x00, 0x2f, 0x00, 0x00},/* ! */
{0x00, 0x00, 0x07, 0x00, 0x07, 0x00},/* " */
{0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14},/* # */
{0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12},/* $ */
{0x00, 0x62, 0x64, 0x08, 0x13, 0x23},/* % */
{0x00, 0x36, 0x49, 0x55, 0x22, 0x50},/* & */
{0x00, 0x00, 0x05, 0x03, 0x00, 0x00},/* ' */
{0x00, 0x00, 0x1c, 0x22, 0x41, 0x00},/* ( */
{0x00, 0x00, 0x41, 0x22, 0x1c, 0x00},/* ) */
{0x00, 0x14, 0x08, 0x3E, 0x08, 0x14},/* * */
{0x00, 0x08, 0x08, 0x3E, 0x08, 0x08},/* + */
{0x00, 0x00, 0x00, 0xA0, 0x60, 0x00},/* , */
{0x00, 0x08, 0x08, 0x08, 0x08, 0x08},/* - */
{0x00, 0x00, 0x60, 0x60, 0x00, 0x00},/* . */
{0x00, 0x20, 0x10, 0x08, 0x04, 0x02},/* / */
{0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E},/* 0 */
{0x00, 0x00, 0x42, 0x7F, 0x40, 0x00},/* 1 */
{0x00, 0x42, 0x61, 0x51, 0x49, 0x46},/* 2 */
{0x00, 0x21, 0x41, 0x45, 0x4B, 0x31},/* 3 */
{0x00, 0x18, 0x14, 0x12, 0x7F, 0x10},/* 4 */
{0x00, 0x27, 0x45, 0x45, 0x45, 0x39},/* 5 */
{0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30},/* 6 */
{0x00, 0x01, 0x71, 0x09, 0x05, 0x03},/* 7 */
{0x00, 0x36, 0x49, 0x49, 0x49, 0x36},/* 8 */
{0x00, 0x06, 0x49, 0x49, 0x29, 0x1E},/* 9 */
{0x00, 0x00, 0x36, 0x36, 0x00, 0x00},/* : */
{0x00, 0x00, 0x56, 0x36, 0x00, 0x00},/* ; */
{0x00, 0x08, 0x14, 0x22, 0x41, 0x00},/* < */
{0x00, 0x14, 0x14, 0x14, 0x14, 0x14},/* = */
{0x00, 0x00, 0x41, 0x22, 0x14, 0x08},/* > */
{0x00, 0x02, 0x01, 0x51, 0x09, 0x06},/* ? */
{0x00, 0x32, 0x49, 0x59, 0x51, 0x3E},/* @ */
{0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C},/* A */
{0x00, 0x7F, 0x49, 0x49, 0x49, 0x36},/* B */
{0x00, 0x3E, 0x41, 0x41, 0x41, 0x22},/* C */
{0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C},/* D */
{0x00, 0x7F, 0x49, 0x49, 0x49, 0x41},/* E */
{0x00, 0x7F, 0x09, 0x09, 0x09, 0x01},/* F */
{0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A},/* G */
{0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F},/* H */
{0x00, 0x00, 0x41, 0x7F, 0x41, 0x00},/* I */
{0x00, 0x20, 0x40, 0x41, 0x3F, 0x01},/* J */
{0x00, 0x7F, 0x08, 0x14, 0x22, 0x41},/* K */
{0x00, 0x7F, 0x40, 0x40, 0x40, 0x40},/* L */
{0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F},/* M */
{0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F},/* N */
{0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E},/* O */
{0x00, 0x7F, 0x09, 0x09, 0x09, 0x06},/* P */
{0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E},/* Q */
{0x00, 0x7F, 0x09, 0x19, 0x29, 0x46},/* R */
{0x00, 0x46, 0x49, 0x49, 0x49, 0x31},/* S */
{0x00, 0x01, 0x01, 0x7F, 0x01, 0x01},/* T */
{0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F},/* U */
{0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F},/* V */
{0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F},/* W */
{0x00, 0x63, 0x14, 0x08, 0x14, 0x63},/* X */
{0x00, 0x07, 0x08, 0x70, 0x08, 0x07},/* Y */
{0x00, 0x61, 0x51, 0x49, 0x45, 0x43},/* Z */
{0x00, 0x00, 0x7F, 0x41, 0x41, 0x00},/* [ */
{0x00, 0x55, 0x2A, 0x55, 0x2A, 0x55},/* 55 */
{0x00, 0x00, 0x41, 0x41, 0x7F, 0x00},/* ] */
{0x00, 0x04, 0x02, 0x01, 0x02, 0x04},/* ^ */
{0x00, 0x40, 0x40, 0x40, 0x40, 0x40},/* _ */
{0x00, 0x00, 0x01, 0x02, 0x04, 0x00},/* ' */
{0x00, 0x20, 0x54, 0x54, 0x54, 0x78},/* a */
{0x00, 0x7F, 0x48, 0x44, 0x44, 0x38},/* b */
{0x00, 0x38, 0x44, 0x44, 0x44, 0x20},/* c */
{0x00, 0x38, 0x44, 0x44, 0x48, 0x7F},/* d */
{0x00, 0x38, 0x54, 0x54, 0x54, 0x18},/* e */
{0x00, 0x08, 0x7E, 0x09, 0x01, 0x02},/* f */
{0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C},/* g */
{0x00, 0x7F, 0x08, 0x04, 0x04, 0x78},/* h */
{0x00, 0x00, 0x44, 0x7D, 0x40, 0x00},/* i */
{0x00, 0x40, 0x80, 0x84, 0x7D, 0x00},/* j */
{0x00, 0x7F, 0x10, 0x28, 0x44, 0x00},/* k */
{0x00, 0x00, 0x41, 0x7F, 0x40, 0x00},/* l */
{0x00, 0x7C, 0x04, 0x18, 0x04, 0x78},/* m */
{0x00, 0x7C, 0x08, 0x04, 0x04, 0x78},/* n */
{0x00, 0x38, 0x44, 0x44, 0x44, 0x38},/* o */
{0x00, 0xFC, 0x24, 0x24, 0x24, 0x18},/* p */
{0x00, 0x18, 0x24, 0x24, 0x18, 0xFC},/* q */
{0x00, 0x7C, 0x08, 0x04, 0x04, 0x08},/* r */
{0x00, 0x48, 0x54, 0x54, 0x54, 0x20},/* s */
{0x00, 0x04, 0x3F, 0x44, 0x40, 0x20},/* t */
{0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C},/* u */
{0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C},/* v */
{0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C},/* w */
{0x00, 0x44, 0x28, 0x10, 0x28, 0x44},/* x */
{0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C},/* y */
{0x00, 0x44, 0x64, 0x54, 0x4C, 0x44},/* z */
{0x14, 0x14, 0x14, 0x14, 0x14, 0x14},/* horiz lines */
};
/****************************************************************************/
const unsigned char  F8X16[1600] = {

0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x33, 0x30, 0x00, 0x00, 0x00,
0x00, 0x10, 0x0C, 0x06, 0x10, 0x0C, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x40, 0xC0, 0x78, 0x40, 0xC0, 0x78, 0x40, 0x00, 0x04, 0x3F, 0x04, 0x04, 0x3F, 0x04, 0x04, 0x00,
0x00, 0x70, 0x88, 0xFC, 0x08, 0x30, 0x00, 0x00, 0x00, 0x18, 0x20, 0xFF, 0x21, 0x1E, 0x00, 0x00,
0xF0, 0x08, 0xF0, 0x00, 0xE0, 0x18, 0x00, 0x00, 0x00, 0x21, 0x1C, 0x03, 0x1E, 0x21, 0x1E, 0x00,
0x00, 0xF0, 0x08, 0x88, 0x70, 0x00, 0x00, 0x00, 0x1E, 0x21, 0x23, 0x24, 0x19, 0x27, 0x21, 0x10,
0x10, 0x16, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xE0, 0x18, 0x04, 0x02, 0x00, 0x00, 0x00, 0x00, 0x07, 0x18, 0x20, 0x40, 0x00,
0x00, 0x02, 0x04, 0x18, 0xE0, 0x00, 0x00, 0x00, 0x00, 0x40, 0x20, 0x18, 0x07, 0x00, 0x00, 0x00,
0x40, 0x40, 0x80, 0xF0, 0x80, 0x40, 0x40, 0x00, 0x02, 0x02, 0x01, 0x0F, 0x01, 0x02, 0x02, 0x00,
0x00, 0x00, 0x00, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x1F, 0x01, 0x01, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xB0, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0x60, 0x18, 0x04, 0x00, 0x60, 0x18, 0x06, 0x01, 0x00, 0x00, 0x00,
0x00, 0xE0, 0x10, 0x08, 0x08, 0x10, 0xE0, 0x00, 0x00, 0x0F, 0x10, 0x20, 0x20, 0x10, 0x0F, 0x00,
0x00, 0x10, 0x10, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00,
0x00, 0x70, 0x08, 0x08, 0x08, 0x88, 0x70, 0x00, 0x00, 0x30, 0x28, 0x24, 0x22, 0x21, 0x30, 0x00,
0x00, 0x30, 0x08, 0x88, 0x88, 0x48, 0x30, 0x00, 0x00, 0x18, 0x20, 0x20, 0x20, 0x11, 0x0E, 0x00,
0x00, 0x00, 0xC0, 0x20, 0x10, 0xF8, 0x00, 0x00, 0x00, 0x07, 0x04, 0x24, 0x24, 0x3F, 0x24, 0x00,
0x00, 0xF8, 0x08, 0x88, 0x88, 0x08, 0x08, 0x00, 0x00, 0x19, 0x21, 0x20, 0x20, 0x11, 0x0E, 0x00,
0x00, 0xE0, 0x10, 0x88, 0x88, 0x18, 0x00, 0x00, 0x00, 0x0F, 0x11, 0x20, 0x20, 0x11, 0x0E, 0x00,
0x00, 0x38, 0x08, 0x08, 0xC8, 0x38, 0x08, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x00, 0x00, 0x00, 0x00,
0x00, 0x70, 0x88, 0x08, 0x08, 0x88, 0x70, 0x00, 0x00, 0x1C, 0x22, 0x21, 0x21, 0x22, 0x1C, 0x00,
0x00, 0xE0, 0x10, 0x08, 0x08, 0x10, 0xE0, 0x00, 0x00, 0x00, 0x31, 0x22, 0x22, 0x11, 0x0F, 0x00,
0x00, 0x00, 0x00, 0xC0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x60, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x80, 0x40, 0x20, 0x10, 0x08, 0x00, 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x00,
0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00,
0x00, 0x08, 0x10, 0x20, 0x40, 0x80, 0x00, 0x00, 0x00, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01, 0x00,
0x00, 0x70, 0x48, 0x08, 0x08, 0x08, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x30, 0x36, 0x01, 0x00, 0x00,
0xC0, 0x30, 0xC8, 0x28, 0xE8, 0x10, 0xE0, 0x00, 0x07, 0x18, 0x27, 0x24, 0x23, 0x14, 0x0B, 0x00,
0x00, 0x00, 0xC0, 0x38, 0xE0, 0x00, 0x00, 0x00, 0x20, 0x3C, 0x23, 0x02, 0x02, 0x27, 0x38, 0x20,
0x08, 0xF8, 0x88, 0x88, 0x88, 0x70, 0x00, 0x00, 0x20, 0x3F, 0x20, 0x20, 0x20, 0x11, 0x0E, 0x00,
0xC0, 0x30, 0x08, 0x08, 0x08, 0x08, 0x38, 0x00, 0x07, 0x18, 0x20, 0x20, 0x20, 0x10, 0x08, 0x00,
0x08, 0xF8, 0x08, 0x08, 0x08, 0x10, 0xE0, 0x00, 0x20, 0x3F, 0x20, 0x20, 0x20, 0x10, 0x0F, 0x00,
0x08, 0xF8, 0x88, 0x88, 0xE8, 0x08, 0x10, 0x00, 0x20, 0x3F, 0x20, 0x20, 0x23, 0x20, 0x18, 0x00,
0x08, 0xF8, 0x88, 0x88, 0xE8, 0x08, 0x10, 0x00, 0x20, 0x3F, 0x20, 0x00, 0x03, 0x00, 0x00, 0x00,
0xC0, 0x30, 0x08, 0x08, 0x08, 0x38, 0x00, 0x00, 0x07, 0x18, 0x20, 0x20, 0x22, 0x1E, 0x02, 0x00,
0x08, 0xF8, 0x08, 0x00, 0x00, 0x08, 0xF8, 0x08, 0x20, 0x3F, 0x21, 0x01, 0x01, 0x21, 0x3F, 0x20,
0x00, 0x08, 0x08, 0xF8, 0x08, 0x08, 0x00, 0x00, 0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00,
0x00, 0x00, 0x08, 0x08, 0xF8, 0x08, 0x08, 0x00, 0xC0, 0x80, 0x80, 0x80, 0x7F, 0x00, 0x00, 0x00,
0x08, 0xF8, 0x88, 0xC0, 0x28, 0x18, 0x08, 0x00, 0x20, 0x3F, 0x20, 0x01, 0x26, 0x38, 0x20, 0x00,
0x08, 0xF8, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x3F, 0x20, 0x20, 0x20, 0x20, 0x30, 0x00,
0x08, 0xF8, 0xF8, 0x00, 0xF8, 0xF8, 0x08, 0x00, 0x20, 0x3F, 0x00, 0x3F, 0x00, 0x3F, 0x20, 0x00,
0x08, 0xF8, 0x30, 0xC0, 0x00, 0x08, 0xF8, 0x08, 0x20, 0x3F, 0x20, 0x00, 0x07, 0x18, 0x3F, 0x00,
0xE0, 0x10, 0x08, 0x08, 0x08, 0x10, 0xE0, 0x00, 0x0F, 0x10, 0x20, 0x20, 0x20, 0x10, 0x0F, 0x00,
0x08, 0xF8, 0x08, 0x08, 0x08, 0x08, 0xF0, 0x00, 0x20, 0x3F, 0x21, 0x01, 0x01, 0x01, 0x00, 0x00,
0xE0, 0x10, 0x08, 0x08, 0x08, 0x10, 0xE0, 0x00, 0x0F, 0x18, 0x24, 0x24, 0x38, 0x50, 0x4F, 0x00,
0x08, 0xF8, 0x88, 0x88, 0x88, 0x88, 0x70, 0x00, 0x20, 0x3F, 0x20, 0x00, 0x03, 0x0C, 0x30, 0x20,
0x00, 0x70, 0x88, 0x08, 0x08, 0x08, 0x38, 0x00, 0x00, 0x38, 0x20, 0x21, 0x21, 0x22, 0x1C, 0x00,
0x18, 0x08, 0x08, 0xF8, 0x08, 0x08, 0x18, 0x00, 0x00, 0x00, 0x20, 0x3F, 0x20, 0x00, 0x00, 0x00,
0x08, 0xF8, 0x08, 0x00, 0x00, 0x08, 0xF8, 0x08, 0x00, 0x1F, 0x20, 0x20, 0x20, 0x20, 0x1F, 0x00,
0x08, 0x78, 0x88, 0x00, 0x00, 0xC8, 0x38, 0x08, 0x00, 0x00, 0x07, 0x38, 0x0E, 0x01, 0x00, 0x00,
0xF8, 0x08, 0x00, 0xF8, 0x00, 0x08, 0xF8, 0x00, 0x03, 0x3C, 0x07, 0x00, 0x07, 0x3C, 0x03, 0x00,
0x08, 0x18, 0x68, 0x80, 0x80, 0x68, 0x18, 0x08, 0x20, 0x30, 0x2C, 0x03, 0x03, 0x2C, 0x30, 0x20,
0x08, 0x38, 0xC8, 0x00, 0xC8, 0x38, 0x08, 0x00, 0x00, 0x00, 0x20, 0x3F, 0x20, 0x00, 0x00, 0x00,
0x10, 0x08, 0x08, 0x08, 0xC8, 0x38, 0x08, 0x00, 0x20, 0x38, 0x26, 0x21, 0x20, 0x20, 0x18, 0x00,
0x00, 0x00, 0x00, 0xFE, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x7F, 0x40, 0x40, 0x40, 0x00,
0x00, 0x0C, 0x30, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x06, 0x38, 0xC0, 0x00,
0x00, 0x02, 0x02, 0x02, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x40, 0x7F, 0x00, 0x00, 0x00,
0x00, 0x00, 0x04, 0x02, 0x02, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x00, 0x02, 0x02, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x19, 0x24, 0x22, 0x22, 0x22, 0x3F, 0x20,
0x08, 0xF8, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x11, 0x20, 0x20, 0x11, 0x0E, 0x00,
0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x0E, 0x11, 0x20, 0x20, 0x20, 0x11, 0x00,
0x00, 0x00, 0x00, 0x80, 0x80, 0x88, 0xF8, 0x00, 0x00, 0x0E, 0x11, 0x20, 0x20, 0x10, 0x3F, 0x20,
0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x1F, 0x22, 0x22, 0x22, 0x22, 0x13, 0x00,
0x00, 0x80, 0x80, 0xF0, 0x88, 0x88, 0x88, 0x18, 0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00,
0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x6B, 0x94, 0x94, 0x94, 0x93, 0x60, 0x00,
0x08, 0xF8, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00, 0x20, 0x3F, 0x21, 0x00, 0x00, 0x20, 0x3F, 0x20,
0x00, 0x80, 0x98, 0x98, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00,
0x00, 0x00, 0x00, 0x80, 0x98, 0x98, 0x00, 0x00, 0x00, 0xC0, 0x80, 0x80, 0x80, 0x7F, 0x00, 0x00,
0x08, 0xF8, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00, 0x20, 0x3F, 0x24, 0x02, 0x2D, 0x30, 0x20, 0x00,
0x00, 0x08, 0x08, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x3F, 0x20, 0x20, 0x00, 0x00,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x20, 0x3F, 0x20, 0x00, 0x3F, 0x20, 0x00, 0x3F,
0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00, 0x20, 0x3F, 0x21, 0x00, 0x00, 0x20, 0x3F, 0x20,
0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x1F, 0x20, 0x20, 0x20, 0x20, 0x1F, 0x00,
0x80, 0x80, 0x00, 0x80, 0x80, 0x00, 0x00, 0x00, 0x80, 0xFF, 0xA1, 0x20, 0x20, 0x11, 0x0E, 0x00,
0x00, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x0E, 0x11, 0x20, 0x20, 0xA0, 0xFF, 0x80,
0x80, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x00, 0x20, 0x20, 0x3F, 0x21, 0x20, 0x00, 0x01, 0x00,
0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x33, 0x24, 0x24, 0x24, 0x24, 0x19, 0x00,
0x00, 0x80, 0x80, 0xE0, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1F, 0x20, 0x20, 0x00, 0x00,
0x80, 0x80, 0x00, 0x00, 0x00, 0x80, 0x80, 0x00, 0x00, 0x1F, 0x20, 0x20, 0x20, 0x10, 0x3F, 0x20,
0x80, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x80, 0x00, 0x01, 0x0E, 0x30, 0x08, 0x06, 0x01, 0x00,
0x80, 0x80, 0x00, 0x80, 0x00, 0x80, 0x80, 0x80, 0x0F, 0x30, 0x0C, 0x03, 0x0C, 0x30, 0x0F, 0x00,
0x00, 0x80, 0x80, 0x00, 0x80, 0x80, 0x80, 0x00, 0x00, 0x20, 0x31, 0x2E, 0x0E, 0x31, 0x20, 0x00,
0x80, 0x80, 0x80, 0x00, 0x00, 0x80, 0x80, 0x80, 0x80, 0x81, 0x8E, 0x70, 0x18, 0x06, 0x01, 0x00,
0x00, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x21, 0x30, 0x2C, 0x22, 0x21, 0x30, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0x7C, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0x40, 0x40,
0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
0x00, 0x02, 0x02, 0x7C, 0x80, 0x00, 0x00, 0x00, 0x00, 0x40, 0x40, 0x3F, 0x00, 0x00, 0x00, 0x00,
0x00, 0x06, 0x01, 0x01, 0x02, 0x02, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};

const unsigned char  Hzk[8][16] = {

{0x80, 0x70, 0x00, 0xFF, 0x20, 0x10, 0x00, 0xFE, 0x22, 0x22, 0x22, 0x22, 0x22, 0xE2, 0x02, 0x00},
{0x80, 0x60, 0x18, 0x07, 0x08, 0x30, 0x00, 0x7F, 0x44, 0x44, 0x44, 0x44, 0x44, 0x47, 0x40, 0x00},

{0x04, 0x04, 0x04, 0x04, 0x1F, 0x04, 0x24, 0x44, 0x84, 0x04, 0x1F, 0x04, 0x04, 0x04, 0x04, 0x00},
{0x10, 0x08, 0x06, 0x00, 0x00, 0x3F, 0x40, 0x40, 0x40, 0x40, 0x40, 0x70, 0x01, 0x02, 0x0C, 0x00},

{0x24, 0x24, 0xA4, 0xFE, 0xA3, 0x22, 0x00, 0x22, 0xCC, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00},
{0x08, 0x06, 0x01, 0xFF, 0x00, 0x01, 0x04, 0x04, 0x04, 0x04, 0x04, 0xFF, 0x02, 0x02, 0x02, 0x00},

{0x10, 0x10, 0x10, 0xFF, 0x10, 0x90, 0x08, 0x88, 0x88, 0x88, 0xFF, 0x88, 0x88, 0x88, 0x08, 0x00},
{0x04, 0x44, 0x82, 0x7F, 0x01, 0x80, 0x80, 0x40, 0x43, 0x2C, 0x10, 0x28, 0x46, 0x81, 0x80, 0x00},

};

struct ssd1306_data {
#ifdef CONFIG_SSD1306_DEV_TYPE_SPI
	struct device *reset_gpio;
	struct device *command_data_gpio;
	struct device *spi_dev;
	struct spi_config spi_config;
#else
#error "SSD1306 device type not specified"
#endif
};
#define SSD1306_DATA 1
#define SSD1306_CMD 0
#define SSD1306_CMD_DATA_PIN_DATA 1
#define SSD1306_CMD_DATA_PIN_COMMAND 0
#define SSD1306_MAX_COLUMN 128
#define SSD1306_CHAR_SIZE 16
#define MISO_FUNC 0x3025
#define DC_SW_FUNC 0x2000060

static void ssd1306_transmit(struct ssd1306_data *data, u8_t tx_data, u8_t type)
{
	int err;
	struct device *cd_gpio;

	cd_gpio = device_get_binding(CONFIG_GPIO_ACTS_DEV_NAME);
#ifdef CONFIG_SSD1306_DEV_TYPE_SPI
	struct spi_buf tx_buf = {(void *)&tx_data, 1};

	if (type == SSD1306_CMD) {
		gpio_pin_write(cd_gpio, BOARD_PANEL_SSD1306_DC, SSD1306_CMD_DATA_PIN_COMMAND);

		err = spi_write(&data->spi_config, &tx_buf, 1);

		if (err) {
			SYS_LOG_DBG("Transmit command fail %d\n", err);
		}

	} else {
		gpio_pin_write(cd_gpio, BOARD_PANEL_SSD1306_DC, SSD1306_CMD_DATA_PIN_DATA);

		err = spi_write(&data->spi_config, &tx_buf, 1);

		if (err) {
			SYS_LOG_DBG("Transmit data fail %d\n", err);
		}

	}

	/* idle level high */
	gpio_pin_write(data->command_data_gpio, BOARD_PANEL_SSD1306_DC, 1);

#endif
}

static void ssd1306_set_pos(struct ssd1306_data *data, u8_t x, u8_t y)
{
	ssd1306_transmit(data, 0xb0 + y, SSD1306_CMD);
	ssd1306_transmit(data, x & 0x0f, SSD1306_CMD);
	ssd1306_transmit(data, ((x & 0xf0) >> 4) | 0x10, SSD1306_CMD);
}
void ssd1306_show_char(struct device *dev, u8_t x, u8_t y, u8_t chr)
{
	struct ssd1306_data *data = (struct ssd1306_data *)dev->driver_data;
	u8_t c = 0, i = 0;

/* #ifdef CONFIG_SSD1306_DEV_TYPE_SPI */
/* struct device *spi= data->spi_dev; */
/* struct acts_spi_data *spi_data = spi->driver_data; */
/* k_sem_take(&spi_data->spi_sync, -1); */
/* #endif */

	c = chr - ' ';
	if (x > SSD1306_MAX_COLUMN - 1) {
		x = 0;
		y = y + 2;
	}

	if (SSD1306_CHAR_SIZE == 16) {
		ssd1306_set_pos(data, x, y);

		for (i = 0; i < 8; i++)
			ssd1306_transmit(data, F8X16[c * 16 + i], SSD1306_DATA);

		ssd1306_set_pos(data, x, y + 1);

		for (i = 0; i < 8; i++)
			ssd1306_transmit(data, F8X16[c * 16 + i + 8], SSD1306_DATA);
	} else {
		ssd1306_set_pos(data, x, y + 1);

		for (i = 0; i < 6; i++)
			ssd1306_transmit(data, F6x8[c][i], SSD1306_DATA);
	}

/* #ifdef CONFIG_SSD1306_DEV_TYPE_SPI */
/* k_sem_give(&spi_data->spi_sync); */
/* #endif */

}

static u32_t ssd1306_pow(u8_t m, u8_t n)
{
	u32_t result = 1;

	while (n--)
		result *= m;

	return result;
}

void ssd1306_show_num(struct device *dev, u8_t x, u8_t y,
				u32_t num, u8_t len, u8_t size2)
{
	u8_t t, temp;
	u8_t enshow = 0;

	for (t = 0; t < len; t++) {
		temp = (num / ssd1306_pow(10, len - t - 1)) % 10;
		if (enshow == 0 && t < (len - 1)) {
			if (temp == 0) {
				ssd1306_show_char(dev, x + (size2 / 2) * t, y, ' ');
				continue;
			} else {
				enshow = 1;
			}
		}
		ssd1306_show_char(dev, x + (size2 / 2) * t, y, temp + '0');
	}
}

void ssd1306_show_string(struct device *dev, u8_t x, u8_t y, u8_t *chr)
{
	u8_t j = 0;

	while (chr[j] != '\0') {
		ssd1306_show_char(dev, x, y, chr[j]);
		x += 8;
		if (x > 120) {
			x = 0;
			y += 2;
		}
		j++;
	}
}

void ssd1306_show_chinese(struct device *dev, u8_t x, u8_t y, u8_t no)
{
	struct ssd1306_data *data = (struct ssd1306_data *)dev->driver_data;
	u8_t t, adder = 0;

	ssd1306_set_pos(data, x, y);
	for (t = 0; t < 16; t++) {
		ssd1306_transmit(data, Hzk[2 * no][t], SSD1306_DATA);
		adder += 1;
	}

	ssd1306_set_pos(data, x, y + 1);
	for (t = 0; t < 16; t++) {
		ssd1306_transmit(data, Hzk[2 * no + 1][t], SSD1306_DATA);
		adder += 1;
	}

}

void ssd1306_draw_bmp(struct device *dev, u8_t x0, u8_t y0, u8_t x1, u8_t y1, u8_t BMP[])
{
	struct ssd1306_data *data = (struct ssd1306_data *)dev->driver_data;

	u32_t j = 0;
	u8_t x, y;

	if (y1 % 8 == 0)
		y = y1 / 8;
	else
		y = y1 / 8 + 1;

	for (y = y0; y < y1; y++) {
		ssd1306_set_pos(data, x0, y);
		for (x = x0; x < x1; x++)
			ssd1306_transmit(data, BMP[j++], SSD1306_DATA);
	}


}

void ssd1306_scroll(struct device *dev)
{
	struct ssd1306_data *data = (struct ssd1306_data *)dev->driver_data;

	ssd1306_transmit(data, 0x2E, SSD1306_CMD);
	ssd1306_transmit(data, 0x27, SSD1306_CMD);
	ssd1306_transmit(data, 0x00, SSD1306_CMD);
	ssd1306_transmit(data, 0x00, SSD1306_CMD);
	ssd1306_transmit(data, 0x00, SSD1306_CMD);
	ssd1306_transmit(data, 0x01, SSD1306_CMD);
	ssd1306_transmit(data, 0x00, SSD1306_CMD);
	ssd1306_transmit(data, 0xFF, SSD1306_CMD);
	ssd1306_transmit(data, 0x2F, SSD1306_CMD);

}

void ssd1306_display_on(struct device *dev)
{
	struct ssd1306_data *data = (struct ssd1306_data *)dev->driver_data;

	SYS_LOG_DBG("Turning display on");
	ssd1306_transmit(data, 0X8D, SSD1306_CMD);
	ssd1306_transmit(data, 0X14, SSD1306_CMD);
	ssd1306_transmit(data, 0XAF, SSD1306_CMD);

}

void ssd1306_display_off(struct device *dev)
{
	struct ssd1306_data *data = (struct ssd1306_data *)dev->driver_data;

	SYS_LOG_DBG("Turning display off");
	ssd1306_transmit(data, 0X8D, SSD1306_CMD);
	ssd1306_transmit(data, 0X14, SSD1306_CMD);
	ssd1306_transmit(data, 0XAE, SSD1306_CMD);

}

void ssd1306_clear(struct device *dev)
{


	struct ssd1306_data *data = (struct ssd1306_data *)dev->driver_data;
	u8_t i, n;

	for (i = 0; i < 8; i++) {
		ssd1306_transmit(data, 0xb0 + i, SSD1306_CMD);
		ssd1306_transmit(data, 0x00, SSD1306_CMD);
		ssd1306_transmit(data, 0x10, SSD1306_CMD);
		for (n = 0; n < 128; n++)
			ssd1306_transmit(data, 0, SSD1306_DATA);
	}
}
static struct spi_func ssd_1306_cs_func = {
.cs_func = NULL,
.dev_spi_user = CONFIG_SSD1306_DEV_NAME,
.driver_or_controller = 0,
};

void ssd1306_oled_init(struct device *dev, spi_cs_func func)
{
	struct ssd1306_data *data = (struct ssd1306_data *)dev->driver_data;

	SYS_LOG_DBG("Resetting display driver");
	gpio_pin_write(data->reset_gpio, BOARD_PANEL_SSD1306_RES, 1);
	k_sleep(100);
	gpio_pin_write(data->reset_gpio, BOARD_PANEL_SSD1306_RES, 0);
	k_sleep(200);
	gpio_pin_write(data->reset_gpio, BOARD_PANEL_SSD1306_RES, 1);
	k_sleep(200);

	ssd_1306_cs_func.cs_func = func;
	data->spi_config.cs_func = &ssd_1306_cs_func;

	ssd1306_transmit(data, 0xAE, SSD1306_CMD);

	ssd1306_transmit(data, 0x00, SSD1306_CMD);
	ssd1306_transmit(data, 0x10, SSD1306_CMD);
	ssd1306_transmit(data, 0x40, SSD1306_CMD);
	ssd1306_transmit(data, 0xB0, SSD1306_CMD);

	ssd1306_transmit(data, 0x81, SSD1306_CMD);
	ssd1306_transmit(data, 0xFF, SSD1306_CMD);

	ssd1306_transmit(data, 0xA0, SSD1306_CMD);
	ssd1306_transmit(data, 0xA6, SSD1306_CMD);

	ssd1306_transmit(data, 0xA8, SSD1306_CMD);
	ssd1306_transmit(data, 0x3F, SSD1306_CMD);

	ssd1306_transmit(data, 0xC0, SSD1306_CMD);

	ssd1306_transmit(data, 0xD3, SSD1306_CMD);
	ssd1306_transmit(data, 0x00, SSD1306_CMD);

	ssd1306_transmit(data, 0xD5, SSD1306_CMD);
	ssd1306_transmit(data, 0x80, SSD1306_CMD);

	ssd1306_transmit(data, 0xD9, SSD1306_CMD);
	ssd1306_transmit(data, 0xF1, SSD1306_CMD);

	ssd1306_transmit(data, 0xDA, SSD1306_CMD);
	ssd1306_transmit(data, 0x12, SSD1306_CMD);

	ssd1306_transmit(data, 0xDB, SSD1306_CMD);
	ssd1306_transmit(data, 0x40, SSD1306_CMD);

	ssd1306_transmit(data, 0x8D, SSD1306_CMD);
	ssd1306_transmit(data, 0x14, SSD1306_CMD);

	ssd1306_transmit(data, 0xAF, SSD1306_CMD);
}
static int ssd1306_dc_pad_func_switch(int cmd, int pin)
{
	if (sys_read32(0xc0090000+pin*4) == DC_SW_FUNC)
		return 0;

	sys_write32(DC_SW_FUNC, GPIO_REG_BASE+pin*4);

	return 0;
}

static struct spi_cs_control ssd1306_cs;
static struct spi_cd_miso ssd1306_dc;

static int ssd1306_init(struct device *dev)
{
	struct ssd1306_data *data = (struct ssd1306_data *)dev->driver_data;

#ifdef CONFIG_SSD1306_DEV_TYPE_SPI

	data->spi_dev = device_get_binding(CONFIG_SPI_1_NAME);
	if (data->spi_dev == NULL) {
		SYS_LOG_ERR("Could not get SPI device for SSD1306");
		return -EPERM;
	}

	data->spi_config.dev = data->spi_dev;
	data->spi_config.frequency = 80000000;
	data->spi_config.operation = SPI_WORD_SET(8) | SPI_TRANSFER_MSB | SPI_OP_MODE_MASTER | SPI_MODE_CPOL | SPI_MODE_CPHA;
	data->spi_config.slave = 0;
	data->spi_config.vendor = 0;

	ssd1306_cs.delay = 0;
	ssd1306_cs.gpio_dev = device_get_binding(CONFIG_GPIO_ACTS_DEV_NAME);
	ssd1306_cs.gpio_pin = BOARD_PANEL_SSD1306_CS;
	data->spi_config.cs =  &ssd1306_cs;

	ssd1306_dc.dc_or_miso = 0;
	ssd1306_dc.pin = BOARD_PANEL_SSD1306_DC;
	ssd1306_dc.dc_func = ssd1306_dc_pad_func_switch;
	data->spi_config.dc_func_switch = &ssd1306_dc;

	data->reset_gpio =  device_get_binding(CONFIG_GPIO_ACTS_DEV_NAME);
	data->command_data_gpio = device_get_binding(CONFIG_GPIO_ACTS_DEV_NAME);

	if (data->reset_gpio == NULL) {
		SYS_LOG_ERR("Could not get GPIO port for SSD1306 reset");
		return -EPERM;
	}

	gpio_pin_configure(data->reset_gpio, BOARD_PANEL_SSD1306_RES, GPIO_DIR_OUT);
	gpio_pin_configure(data->command_data_gpio, BOARD_PANEL_SSD1306_RES, GPIO_DIR_OUT);

#endif

	SYS_LOG_DBG("Initializing LCD\n");

	dev->driver_api = (void *)1;

	return 0;
}

static struct ssd1306_data ssd1306_data;

DEVICE_AND_API_INIT(ssd1306,CONFIG_SSD1306_DEV_NAME, ssd1306_init, &ssd1306_data, NULL, POST_KERNEL, 80, NULL);
